function route(handle, pathname) {
	console.log("About to route a request for " + pathname);
	if (typeof handle[pathname] === 'function') {
		handle[pathname]();
	} else {
		console.log("No request handler found for " + pathname);
	}
}

function index(config, res, query) {
	res.render('index', {}, function(err, html) {
		res.send(JSON.stringify({
			status: 1
		}));
	});
}

function err(res, type) {
	res.render(type, {});
}

exports.route = route;
exports.index = index;
exports.err = err;

class Cache {
	constructor() {
		this.data = {};
		return this;
	}
	commit(data) {
		extend(this.data, data);
		return this;
	}
	get(name) {
		return this.data[name];
	}
	remove(name) {
		if (this.data[name])
			delete this.data[name];
		return this;
	}
	has(name) {
		return (name in this.data);
	}
}

var cache = new Cache();

var request = require('request'),
	FeedParser = require('feedparser'),
	rssSite = {},
	Iconv = require('iconv-lite'),
	fs = require('fs'),
	path = require('path'),
	grunt = require('grunt'),
	dir = "rss" + getTime(new Date(), "yyyyMMdd"),
	hasOwn = {}.hasOwnProperty,
	Segment = require('segment');

function isPlainObject(obj) {
	var key;
	if (!obj || typeof obj !== "object" || obj.nodeType) {
		return false;
	}
	try {
		if (obj.constructor &&
			!hasOwn.call(obj, "constructor") &&
			!hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
			return false;
		}
	} catch (e) {
		return false;
	}
	for (key in obj) {}
	return key === undefined || hasOwn.call(obj, key);
}

function getTime(d, pattern) {
	d = d ? new Date(d) : new Date();
	pattern = pattern || 'yyyy-MM-dd';
	var y = d.getFullYear().toString(),
		o = {
			M: d.getMonth() + 1,
			d: d.getDate(),
			h: d.getHours(),
			m: d.getMinutes(),
			s: d.getSeconds()
		};
	pattern = pattern.replace(/(y+)/ig, function(a, b) {
		return y.substr(4 - Math.min(4, b.length));
	});
	for (var i in o) {
		pattern = pattern.replace(new RegExp('(' + i + '+)', 'g'), function(a, b) {
			return (o[i] < 10 && b.length > 1) ? '0' + o[i] : o[i];
		});
	}
	return pattern;
}

function stringify(obj) {
	//console.log(obj)
	if (null === obj)
		return "null";
	if ("string" !== typeof obj && "undefined" !== typeof obj && obj.toJSON)
		return obj.toJSON();
	var type = (Array.isArray || _instanceOf(Array))(obj) && "array" || typeof obj;
	//console.log(type)
	switch (type) {
		case "string":
			return '"' + obj.replace(/\"/gim, "\'").replace(/\s+/gim, " ").replace(/[\r\n\t\\]+/gim, function(a) {
				return "\\" + a;
			}) + '"';
		case "number":
			var ret = obj.toString();
			return /N/.test(ret) ? "null" : ret;
		case "boolean":
			return obj.toString();
		case "date":
			return "new Date(" + obj.getTime() + ")";
		case "array":
			for (var ar = [], i = 0; i < obj.length; i++)
				ar[i] = stringify(obj[i]);
			return "[" + ar.join(",") + "]";
		case "object":
			//console.log(isPlainObject(obj), obj)
			if (isPlainObject(obj)) {
				ar = [];
				for (var i in obj)
					ar.push('"' + i.replace(/[\"\r\n\t\\]+/gim, function(a) {
						return "\\" + a
					}) + '":' + stringify(obj[i]));
				return "{" + ar.join(",") + "}"
			}
	}
	return "null"
}

var startTime = new Date().getTime();

exports.getChannels = function(res, query) {
	var b = query.callback;
	var channel = grunt.file.readJSON("user/channel.json");
	res.send(b ? b + "(" + JSON.stringify({
		status: 1,
		data: channel.list,
		total: channel.list.length || 0
	}) + ")" : {
		status: 1,
		data: channel.list,
		total: channel.list.length || 0
	});
}

function fetchKeys(data) {
	var keys_data = cache.get("keys") || {},
		item_keys = [],
		length = 0;
	for (var x = 0; x < data.length; x++) {
		var item = data[x];
		var keys = item.title.split(' ');

		for (var i = 0; i < keys.length; i++) {
			typeof keys_data[keys[i]] !== "undefined" ? (keys_data[keys[i]] += 1, keys_data[keys[i]] > 10 && item_keys.push(keys[i])) : (keys_data[keys[i]] = 1);
		}

	}
	if (grunt.file.exists(path.resolve("user/keys.json"))) {
		var file_keys = grunt.file.readJSON(path.resolve("user/keys.json"));
		if (file_keys && file_keys.data) {
			extend(keys_data, file_keys.data);
		}
		if (file_keys && typeof file_keys.length != "undefined") {
			length += file_keys.length;
		} else {
			length += 1;
		}
	}

	cache.commit({
		keys: keys_data
	});

	grunt.file.write(path.resolve("user/keys.json"), "{\"data\":" + stringify(keys_data) + ", \"length\":" + length + "}");
}

var otherServe = "http://47.93.99.52/channel?day={{day}}&channel={{channel}}&count={{count}}&pagenum={{pagenum}}&key={{key}}&type={{type}}&datatype={{datatype}}"
function tmpl(b, a){
	for (var n in a) b = b.replace(new RegExp("{{\\s*"+n+"\\s*}}", "gim"), a[n]);
	return b;
};

exports.channel = function(res, query) {
	var a = grunt.file.readJSON("user/rss.json"),
		b = query.callback,
		c = query.channel || "baidu",
		l = query.count || 10;

	var day = (query.day || getTime(new Date(), "yyyyMMdd"));
	dir = "rss" + day;
	console.log(query, (new Date().getTime() - parseInt(query.key)) / 1000, 60);

	var bool = (!query.key || query.key === "null" || query.key && (new Date().getTime() - parseInt(query.key)) / 1000 > 60) ? true : false;
	if (bool) {
		startTime = (new Date().getTime());
	}

	var isNow = getTime(new Date(), "yyyyMMdd") === day;
	console.log(!grunt.file.exists(dir) || grunt.file.exists(dir) && !grunt.file.exists(dir + "/" + c + ".json"))
	fetchOtherServerJson(tmpl(otherServe, {
		day: day,
		channel: c,
		count: l,
		pagenum: 0,
		key: query.key || null,
		datatype: query.datatype || "net",
		type: query.type || "web"
	}), c, function(txt, type) {
		console.log(txt)
		txt = txt.data || txt;
		var push = [];
		for (var i = 0; i < l; i++) txt[i] && push.push(txt[i]);
		res.send(b ? b + "(" + JSON.stringify({
			status: 1,
			data: push,
			total: txt.length,
			key: startTime,
			type: type
		}) + ")" : {
			status: 1,
			data: push,
			total: txt.length,
			key: startTime,
			type: type
		});
			//fetchKeys(txt);
	});

	/*a.data[c] && a.data[c].typeId !== 1100 ? fetch(a.data[c].link, a.data[c].typeId, c, day, !grunt.file.exists(dir) || grunt.file.exists(dir) && !grunt.file.exists(dir + "/" + c + ".json") ? true : false, function(txt, type) {
		txt = txt.data || txt;
		var push = [];
		for (var i = 0; i < l; i++) txt[i] && push.push(txt[i]);
		res.send(b ? b + "(" + JSON.stringify({
			status: 1,
			data: push,
			total: txt.length,
			key: startTime,
			type: type
		}) + ")" : {
			status: 1,
			data: push,
			total: txt.length,
			key: startTime,
			type: type
		});
			//fetchKeys(txt);
	}) : a.data[c] && a.data[c].typeId === 1100 ? fetchWeb(res, query, a.data[c].link, a.data[c].typeId, c, day, !isNow || !grunt.file.exists(dir) || grunt.file.exists(dir) && !grunt.file.exists(dir + "/" + c + ".json") ? true : false, function(txt, type) {
		txt = txt.data || txt;
		var push = [];
		for (var i = 0; i < l; i++) txt[i] && push.push(txt[i]);
		res.send(b ? b + "(" + JSON.stringify({
			status: 1,
			data: push,
			total: txt.length,
			key: startTime,
			type: type
		}) + ")" : {
			status: 1,
			data: push,
			total: txt.length,
			key: startTime,
			type: type
		})
			//fetchKeys(txt);
	}) : res.send(b ? b + "(" + JSON.stringify({
		status: 0,
		data: []
	}) + ")" : {
		status: 0,
		data: []
	});*/
};

function fetchOtherServerJson(feed, from, callback) {
	request(feed, function(error, response, body) {
		if (!error && response.statusCode == 200) {
			/*var local_json = grunt.file.exists(path.resolve(dir + "/" + from + ".json")) && grunt.file.readJSON(path.resolve(dir + "/" + from + ".json")) || {
				data: []
			};*/
			var local_json = {
				data: []
			};
			var json = JSON.parse(body);
			console.log(json.data)
			for (var i=0;i<json.data.length;i++) {
				local_json.data.push(json.data[i]);
			}
			//json.data && grunt.file.write(path.resolve(dir + "/" + from + ".json"), "{\"data\":" + JSON.stringify(local_json.data) + "}");
			callback(local_json);
		}
	})
}

exports.intervalTasks = function(res, query) {
	var a = grunt.file.readJSON("user/rss.json"),
		b = query.callback;

	dir = "rss" + getTime(new Date(), "yyyyMMdd");
	for (var i in a.data) {
		fetch(a.data[i].link, a.data[i].typeId, i, true, function(txt) {
			console.log("pull " + i);
		});
	}
	res.send(b ? b + "(" + JSON.stringify({
		status: 1
	}) + ")" : {
		status: 1
	});
}

function extend(a, b) {
	for (var i in b) a[i] = b[i];
	return a;
}

exports.search = function(res, query) {
	dir = "rss" + (query.day || getTime(new Date(), "yyyyMMdd"));
	var files = grunt.file.expand(path.resolve(dir + "/*.json"));
	console.log(files, path.resolve(dir + "/*.json"))
	var k = query.key,
		content = [],
		b = query.callback;
	var seg = new Segment();
	seg.useDefault();
	var result = seg.doSegment(k, {
		simple: true
	});
	for (var n = 0; n < result.length; n++) {
		k = result[n];
		for (var i = 0; i < files.length; i++) {
			var type = /\/([^\/\.]+)\.json/.exec(files[i]);
			console.log(type[1])
			var json = grunt.file.readJSON(files[i]);
			for (var n in json.data) {
				var reg = new RegExp(k, "gim");
				(reg.test(json.data[n].description) || reg.test(json.data[n].title)) && content.push(extend(json.data[n], {
					type: type[1] || ""
				}));
			}
		}
	}
	res.send(b ? b + "(" + JSON.stringify({
		status: 1,
		data: content,
		total: content.length,
		keywords: result
	}) + ")" : {
		status: 1,
		data: content,
		total: content.length,
		keywords: result
	});
};

exports.forgotpassword = function(res, req) {
	var query = req.body;
	//console.log(query);
	if (query) {
		if (!query.email || query.email && query.email.replace(/\s+/gim, "") === "") {
			res.send(JSON.stringify({
				status: 0,
				msg: "email not empty."
			}))
			return;
		}
		if (query.email && !/^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(query.email)) {
			res.send(JSON.stringify({
				status: 0,
				msg: "email formate error."
			}))
			return;
		}
		var data = grunt.file.readJSON(path.resolve("user/__userdata.json")) || {
			users: {},
			length: 0
		};
		var email = query.email,
			key = "reset_" + (Math.random(10000) + "").replace(/\./gim, "");
		if (data.users && data.users[email]) {
			sendMail(email, data.users[email], key);
			res.cookie("userReset", encodeURIComponent("k=" + key + ",source=server"), {
				maxAge: 60 * 60 * 1000,
				path: '/',
				domain: '.iliulan.com'
			});
			res.send(JSON.stringify({
				status: 1,
				msg: "Send mail successfully."
			}))
		} else {
			res.send(JSON.stringify({
				status: 0,
				msg: "no email error."
			}))
		}
	} else {
		res.send(JSON.stringify({
			status: 0,
			msg: "error."
		}))
	}
};

exports.resetpassword = function(res, req) {
	var query = req.body;
	//console.log(query);
	if (query) {
		if (!query.email || query.email && query.email.replace(/\s+/gim, "") === "") {
			res.send(JSON.stringify({
				status: 0,
				msg: "email not empty."
			}))
			return;
		}
		if (query.email && !/^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(query.email)) {
			res.send(JSON.stringify({
				status: 0,
				msg: "email formate error."
			}))
			return;
		}
		if (!query.password || query.password && query.password.replace(/\s+/gim, "") === "") {
			res.send(JSON.stringify({
				status: 0,
				msg: "password not empty."
			}))
			return;
		}
		if (query.password && !/^[A-Z]+[a-zA-Z0-9]+/.test(query.password)) {
			res.send(JSON.stringify({
				status: 0,
				msg: "password formate error."
			}))
			return;
		}
		if (query.password && query.password.length < 6) {
			res.send(JSON.stringify({
				status: 0,
				msg: "password length error."
			}))
			return;
		}
		var data = grunt.file.readJSON(path.resolve("user/__userdata.json")) || {
			users: {},
			length: 0
		};
		var email = query.email,
			password = query.password;
		if (data.users && data.users[email]) {
			data.users[email].password = md5(password);
			grunt.file.write(path.resolve(dir + "/__userdata.json"), JSON.stringify(data));
			res.cookie("userReset", "", {
				maxAge: -1000,
				path: '/',
				domain: '.iliulan.com'
			});
			res.send(JSON.stringify({
				status: 1,
				msg: "Reset password successfully."
			}))
		} else {
			res.send(JSON.stringify({
				status: 0,
				msg: "no email error."
			}))
		}
	} else {
		res.send(JSON.stringify({
			status: 0,
			msg: "error."
		}))
	}
};

exports.signin = function(res, req) {
	var query = req.body;
	//console.log(query);
	if (query) {
		if (!query.user || query.user && query.user.replace(/\s+/gim, "") === "") {
			res.send(JSON.stringify({
				status: 0,
				msg: "user not empty."
			}))
			return;
		}
		if (query.user && !/^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(query.user)) {
			res.send(JSON.stringify({
				status: 0,
				msg: "email formate error."
			}))
			return;
		}
		if (!query.password || query.password && query.password.replace(/\s+/gim, "") === "") {
			res.send(JSON.stringify({
				status: 0,
				msg: "password not empty."
			}))
			return;
		}
		if (query.password && !/^[A-Z]+[a-zA-Z0-9]+/.test(query.password)) {
			res.send(JSON.stringify({
				status: 0,
				msg: "password formate error."
			}))
			return;
		}
		if (query.password && query.password.length < 6) {
			res.send(JSON.stringify({
				status: 0,
				msg: "password length error."
			}))
			return;
		}
		var data = grunt.file.readJSON(path.resolve("user/__userdata.json")) || {
			users: {},
			length: 0
		};

		if (data && data.users) {
			if (data.users[query.user]) {
				var user = data.users[query.user];
				if (user.email != query.user) {
					res.send(JSON.stringify({
						status: 0,
						msg: "user name error."
					}));
					return;
				}
				if (md5(query.password) === user.password) {
					res.send(JSON.stringify({
						status: 0,
						msg: "password error."
					}));
					return;
				}
				req.session.signin = true;
				req.session.user = {
					id: user.id,
					name: user.name,
					email: user.email
				};
				res.cookie("userToken", encodeURIComponent("id=" + user.id + ",name=" + user.name + ",email=" + user.email + ",source=server"), {
					maxAge: 60 * 60 * 1000,
					path: '/',
					domain: '.iliulan.com'
				});

				res.send(JSON.stringify({
					status: 1,
					data: [{
						id: user.id,
						name: user.name,
						email: user.email
					}],
					msg: "signIn ok!"
				}));
			} else {
				req.session.signin = req.session.user = false;
				res.send(JSON.stringify({
					status: 0,
					msg: "no user error."
				}))
			}
		}
	} else {
		res.send(JSON.stringify({
			status: 0,
			msg: "error."
		}))
	}
};

exports.signout = function(res, req) {
	var query = req.body;
	//console.log(query);
	if (query) {
		delete req.session.signin;
		delete req.session.user;
		res.cookie("userToken", '', {
			maxAge: -1000,
			path: '/',
			domain: '.iliulan.com'
		});
		res.send(JSON.stringify({
			status: 1,
			msg: "sign out ok."
		}))
	} else {
		res.send(JSON.stringify({
			status: 0,
			msg: "error."
		}))
	}
};

var md5 = function(data) {
	var Buffer = require("buffer").Buffer;
	var buf = new Buffer(data);
	var str = buf.toString("binary");
	var crypto = require("crypto");
	return crypto.createHash("md5WithRSAEncryption").update(str).digest("hex");
};

var count = 3000;
var original = []; //原始数组 
//给原始数组original赋值 
for (var i = 0; i < count; i++) {
	original[i] = i + 1;
}
original.sort(function() {
	return 0.5 - Math.random();
});

exports.createaccount = function(res, req) {
	var query = req.body;
	//console.log(query);
	if (query) {
		/*if (req.session.signin) {
			res.send(JSON.stringify({
				status: 0,
				msg: "error"
			}));
			return;
		}*/
		if (!query.user || query.user && query.user.replace(/\s+/gim, "") === "") {
			res.send(JSON.stringify({
				status: 0,
				msg: "user not empty."
			}))
			return;
		}
		if (query.user && query.user.length < 6) {
			res.send(JSON.stringify({
				status: 0,
				msg: "user length error."
			}))
			return;
		}
		if (!query.email || query.email && query.email.replace(/\s+/gim, "") === "") {
			res.send(JSON.stringify({
				status: 0,
				msg: "email not empty."
			}))
			return;
		}
		if (query.email && !/^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(query.email)) {
			res.send(JSON.stringify({
				status: 0,
				msg: "email formate error."
			}))
			return;
		}
		if (!query.password || query.password && query.password.replace(/\s+/gim, "") === "") {
			res.send(JSON.stringify({
				status: 0,
				msg: "password not empty."
			}))
			return;
		}
		if (query.password && !/^[A-Z]+[a-zA-Z0-9]+/.test(query.password)) {
			res.send(JSON.stringify({
				status: 0,
				msg: "password formate error."
			}))
			return;
		}
		if (query.password && query.password.length < 6) {
			res.send(JSON.stringify({
				status: 0,
				msg: "password length error."
			}))
			return;
		}
		var name = query.user,
			password = md5(query.password),
			email = query.email,
			id = 0;
		var data = grunt.file.readJSON(path.resolve("user/__userdata.json")) || {
			users: {},
			length: 0
		};
		id = data.length + 1;
		if (data.users && !data.users[email]) {
			grunt.file.write(path.resolve("user/__userdata.json"), JSON.stringify(extend(data, {
				users: extend(data.users, {
					[email]: {
						id: id,
						name: name,
						password: password,
						email: email
					}
				}),
				length: id
			})));
			res.cookie("userToken", encodeURIComponent("id=" + id + ",name=" + name + ",email=" + email + ",source=server"), {
				maxAge: 60 * 60 * 1000,
				path: '/',
				domain: '.iliulan.com'
			});
			res.send(JSON.stringify({
				status: 1,
				data: [{
					id: id,
					name: name,
					email: email
				}],
				msg: "create account ok!"
			}));
		} else {
			res.send(JSON.stringify({
				status: 0,
				msg: "The email address is occupied."
			}))
		}
	} else {
		res.send(JSON.stringify({
			status: 0,
			msg: "error."
		}))
	}
};

Array.prototype.delname = function(name, val) {
	var that = this;
	for (var i = 0; i < that.length; i++) {
		if (that[i][name] === val) {
			that.splice(i, 1);
			break;
		}
	}
	return that;
}

exports.delgood = function(res, query) {
	var c = query.type,
		b = query.callback,
		i = query.id,
		u = query.username,
		d = query.userid;
	var day = (query.day || getTime(new Date(), "yyyyMMdd"));
	dir = "rss" + day;
	console.log(query, (new Date().getTime() - parseInt(query.key)) / 1000, 60);
	var filepath = path.resolve(dir + "/" + c + ".json");
	var iscity = false,
		city = "beijing";

	if (!grunt.file.exists(filepath)) {
		var pinyinlite = require('pinyinlite');
		city = pinyinlite(c).join('').split(',')[0];
		console.log(city)
		filepath = path.resolve(dir + "/baiducity_" + city + ".json");
		iscity = true;
	}


	var a = grunt.file.readJSON(filepath);
	if (a && a.data && a.data[i] && u && d) {
		if (a.data[i].goodusers) {
			a.data[i].goodusers = a.data[i].goodusers.delname("gooduser_name", u);
		} else {
			a.data[i].goodusers = [];
		}
		if (a.data[i].goodcount) {
			a.data[i].goodcount -= 1
		} else {
			a.data[i].goodcount = 0
		}
		extend(a.data[i], {
			goodcount: a.data[i].goodcount,
			goodusers: a.data[i].goodusers
		})

		if (!iscity) {
			if (cache.get(day)[c]) {
				console.log("default")
				cache.get(day)[c].data[i] = a.data[i]
			}
		} else {
			if (cache.get(day)["baiducity"] && cache.get(day)["baiducity"][city]) {
				console.log("city")
				cache.get(day)["baiducity"][city].data[i] = a.data[i];
			}
		}
		console.log(cache.get(day))

		grunt.file.write(filepath, JSON.stringify(a));
		res.send(b ? b + "(" + JSON.stringify({
			status: 1,
			data: a.data[i]
		}) + ")" : {
			status: 1,
			data: a.data[i]
		});
	} else {
		res.send(b ? b + "(" + JSON.stringify({
			status: 0,
			data: []
		}) + ")" : {
			status: 0,
			data: []
		});
	}
};

exports.addgood = function(res, query) {
	var c = query.type,
		b = query.callback,
		i = query.id,
		u = query.username,
		d = query.userid;
	var day = (query.day || getTime(new Date(), "yyyyMMdd"));
	dir = "rss" + day;
	console.log(query, (new Date().getTime() - parseInt(query.key)) / 1000, 60);
	var filepath = path.resolve(dir + "/" + c + ".json");
	var iscity = false,
		city = "beijing";

	if (!grunt.file.exists(filepath)) {
		var pinyinlite = require('pinyinlite');
		city = pinyinlite(c).join('').split(',')[0];
		console.log(city)
		filepath = path.resolve(dir + "/baiducity_" + city + ".json");
		iscity = true;
	}

	var a = grunt.file.readJSON(filepath);
	if (a && a.data && a.data[i] && u && d) {
		if (a.data[i].goodusers) {
			a.data[i].goodusers.push({
				gooduser_name: u,
				gooduser_id: d
			})
		} else {
			a.data[i].goodusers = [{
				gooduser_name: u,
				gooduser_id: d
			}];
		}
		if (a.data[i].goodcount) {
			a.data[i].goodcount += 1
		} else {
			a.data[i].goodcount = 1
		}
		extend(a.data[i], {
			goodcount: a.data[i].goodcount,
			goodusers: a.data[i].goodusers,
			lastgoodtime: (new Date()).getTime()
		})

		if (!iscity) {
			if (cache.get(day)[c]) {
				console.log("default")
				cache.get(day)[c].data[i] = a.data[i]
			}
		} else {
			if (cache.get(day)["baiducity"] && cache.get(day)["baiducity"][city]) {
				console.log("city")
				cache.get(day)["baiducity"][city].data[i] = a.data[i];
			}
		}
		console.log(cache.get(day))

		grunt.file.write(filepath, JSON.stringify(a));
		res.send(b ? b + "(" + JSON.stringify({
			status: 1,
			data: a.data[i]
		}) + ")" : {
			status: 1,
			data: a.data[i]
		});
	} else {
		res.send(b ? b + "(" + JSON.stringify({
			status: 0,
			data: []
		}) + ")" : {
			status: 0,
			data: []
		});
	}
};

exports.citynews = function(res, query) {
	var pinyinlite = require('pinyinlite');
	var a = grunt.file.readJSON("user/rss.json"),
		b = query.callback,
		c = "baiducity",
		l = 100,
		city = pinyinlite(query.city).join('').split(',')[0] || "fushun";

	var day = (query.day || getTime(new Date(), "yyyyMMdd"));
	dir = "rss" + day;
	console.log(query, (new Date().getTime() - parseInt(query.key)) / 1000, 60);

	var bool = (!query.key || query.key === "null" || query.key && (new Date().getTime() - parseInt(query.key)) / 1000 > 60) ? true : false;
	if (bool) {
		startTime = (new Date().getTime());
	}

	var isNow = getTime(new Date(), "yyyyMMdd") === day;
	console.log(a.data[c])
	a.data[c] ? fetchCity(a.data[c].link + city, a.data[c].typeId, c, city, day, false, a.data[c].charset || "utf-8", function(txt, type) {
		txt = txt.data || txt;
		var push = [];
		for (var i = 0; i < l; i++) txt[i] && push.push(txt[i]);
		res.send(b ? b + "(" + JSON.stringify({
			status: 1,
			data: push,
			total: txt.length,
			key: startTime,
			type: type
		}) + ")" : {
			status: 1,
			data: push,
			total: txt.length,
			key: startTime,
			type: type
		});
	}) : res.send(b ? b + "(" + JSON.stringify({
		status: 0,
		data: []
	}) + ")" : {
		status: 0,
		data: []
	});
}

function fetch(feed, typeId, from, day, bool, callback) {
	var posts, feedFrom = from;

	function done(err) {
		if (cache.has(day) && cache.get(day)[feedFrom]) {
			console.log("-> read cache. " + day + " - " + feedFrom);
			callback && callback(cache.get(day)[feedFrom], "cache");
		} else if (grunt.file.exists(path.resolve(dir + "/" + feedFrom + ".json"))) {
			console.log("-> read json file. " + feedFrom);
			posts = grunt.file.readJSON(path.resolve(dir + "/" + feedFrom + ".json"));
			cache.commit({
				[day]: {
					[feedFrom]: posts
				}
			});
			callback && callback(posts, "file");
		} else {
			callback(err);
		}
	}
	// Define our streams  
	if (cache.has(day) && cache.get(day)[feedFrom] && bool === false) {
		console.log("-> read cache. " + day + " - " + feedFrom);
		callback && callback(cache.get(day)[feedFrom], "cache");
	} else if (grunt.file.exists(path.resolve(dir + "/" + feedFrom + ".json")) && bool === false) {
		console.log("-> read json file. " + feedFrom);
		posts = grunt.file.readJSON(path.resolve(dir + "/" + feedFrom + ".json"));
		cache.commit({
			[day]: {
				[feedFrom]: posts
			}
		});
		callback && callback(posts, "file");
	} else {
		var req = request(feed, {
			timeout: 10000,
			pool: false
		});
		req.setMaxListeners(50);
		// Some feeds do not response without user-agent and accept headers.  
		req.setHeader('user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36');
		req.setHeader('accept', 'text/html,application/xhtml+xml');

		var feedparser = new FeedParser();

		// Define our handlers  
		req.on('error', done);
		req.on('response', function(res) {
			console.log("-> response, " + feed);
			var stream = this,
				iconv, charset;
			posts = new Array();
			cache.commit({
				[day]: {
					[feedFrom]: posts
				}
			});
			if (res.statusCode != 200) return this.emit('error', new Error('Bad status code'));
			//console.log(res.headers['content-type']);
			charset = "utf-8";
			if (!iconv && charset && !/utf-*8/i.test(charset)) {
				try {
					iconv = new Iconv(charset, 'utf-8');
					iconv.on('error', done);
					stream = this.pipe(iconv);
				} catch (err) {
					this.emit('iconv error', err);
				}
			}
			stream.pipe(feedparser);
		});

		feedparser.on('error', done);
		feedparser.on('end', function(err) {
			console.log("-> read net file. " + feedFrom);
			var content = stringify(posts);
			console.log(path.resolve(dir + "/" + feedFrom + ".json"))
			grunt.file.write(path.resolve(dir + "/" + feedFrom + ".json"), "{\"data\":" + content + "}");
			callback && callback(posts, "net");
		});
		feedparser.on('readable', function() {
			var post;
			while (post = this.read()) {
				posts.push(transToPost(post)); //保存到对象数组  
			}
		});
	}

	function transToPost(post) {
		//var seg = new Segment();
		var title = (post.title + "").replace(/\r|\n/gim, " ").replace(/\s+/gim, " "),
			desc = (post.description + "").replace(/\r|\n/gim, " ").replace(/\s+/gim, " ").replace(/<|>/gim, function(a, b) {
				a = encodeURIComponent(a);
				return a;
			});
		if (desc.replace("...", "") === "") {
			desc = title + "...";
		}

		var result = {
			title: title,
			link: (post.url || post.link || post.alink || "") + "",
			description: desc,
			pubDate: (post.pubDate + "").replace(/\r|\n/gim, " ").replace(/\s+/gim, " "),
			source: /null/.test(post.source) ? feedFrom : (post.source || feedFrom),
			author: (post.author + "").replace(/\r|\n/gim, " ").replace(/\s+/gim, " "),
			typeId: typeId + ""
		};

		if (/\.png|\.jpg|\.gif/.test(desc)) {
			var src = /src\s*\=\s*['"]+(.+\.[png|jpg|gif]+)['"]+/.exec(desc);
			if (src && src.length > 1) {
				extend(result, {
					img: src[1]
				});
			}
		}

		return result;
	}

}

function fetchCity(feed, typeId, from, city, day, bool, local_charset, callback) {
	var posts, feedFrom = from;

	var pinyinlite = require('pinyinlite');
	city = pinyinlite(city.replace(/省|市|区|县|乡|镇|村/gim, "")).join('').split(',')[0];
	console.log(city)

	function done(err) {
		if (cache.has(day) && cache.get(day)[feedFrom] && cache.get(day)[feedFrom][city]) {
			console.log("-> read cache. " + day + " - " + feedFrom + " - " + city);
			callback && callback(cache.get(day)[feedFrom][city], "cache");
		} else if (grunt.file.exists(path.resolve(dir + "/" + feedFrom + "_" + city + ".json"))) {
			console.log("-> read json file. " + feedFrom);
			posts = grunt.file.readJSON(path.resolve(dir + "/" + feedFrom + "_" + city + ".json"));
			cache.commit({
				[day]: {
					[feedFrom]: {
						[city]: posts
					}
				}
			});
			callback && callback(posts, "file");
		} else {
			callback(err);
		}
	}
	// Define our streams  
	if (cache.has(day) && cache.get(day)[feedFrom] && cache.get(day)[feedFrom][city]) {
		console.log("-> read cache. " + day + " - " + feedFrom + " - " + city);
		callback && callback(cache.get(day)[feedFrom][city], "cache");
	} else if (grunt.file.exists(path.resolve(dir + "/" + feedFrom + "_" + city + ".json"))) {
		console.log("-> read json file. " + feedFrom);
		posts = grunt.file.readJSON(path.resolve(dir + "/" + feedFrom + "_" + city + ".json"));
		cache.commit({
			[day]: {
				[feedFrom]: {
					[city]: posts
				}
			}
		});
		callback && callback(posts, "file");
	} else {
		console.log(feed);
		var req = request(feed.replace(/省|市|区|县|乡|镇|村/gim, ""), {
			timeout: 10000,
			pool: false
		});
		req.setMaxListeners(50);
		// Some feeds do not response without user-agent and accept headers.  
		req.setHeader('user-agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/61.0.3163.100 Mobile/13B143 Safari/601.1.46');
		req.setHeader('accept', 'text/html,application/xhtml+xml');

		var feedparser = new FeedParser();

		// Define our handlers  
		req.on('error', done);
		req.on('response', function(res) {
			console.log("-> response, " + feed);
			var stream = this,
				iconv, charset;
			posts = new Array();
			cache.commit({
				[day]: {
					[feedFrom]: {
						[city]: posts
					}
				}
			});
			if (res.statusCode != 200) return this.emit('error', new Error('Bad status code'));
			//console.log(res.headers['content-type']);
			charset = local_charset || "utf-8";
			if (!/utf-*8/i.test(charset)) {
				console.log("iconv")
				try {
					iconv = Iconv.decodeStream(charset);
					iconv.on('error', done);
					stream = this.pipe(iconv);
				} catch (err) {
					console.log(err)
				}
			}
			stream.pipe(feedparser);
		});

		feedparser.on('error', done);
		feedparser.on('end', function(err) {
			console.log("-> read net file. " + feedFrom);
			var content = stringify(posts);
			console.log(path.resolve(dir + "/" + feedFrom + "_" + city + ".json"))
			grunt.file.write(path.resolve(dir + "/" + feedFrom + "_" + city + ".json"), "{\"data\":" + content + "}");
			callback && callback(posts, "net");
		});
		feedparser.on('readable', function() {
			var post;
			while (post = this.read()) {
				posts.push(transToPost(post)); //保存到对象数组  
			}
		});
	}

	function transToPost(post) {
		return {
			title: (post.title + "").replace(/\r|\n/gim, " ").replace(/\s+/gim, " "),
			link: (post.url || post.link || post.alink || "") + "",
			description: (post.description + "").replace(/\r|\n/gim, " ").replace(/\s+/gim, " "),
			pubDate: (post.pubDate + "").replace(/\r|\n/gim, " ").replace(/\s+/gim, " "),
			source: post.source || "",
			author: (post.author + "").replace(/\r|\n/gim, " ").replace(/\s+/gim, " "),
			typeId: typeId + ""
		};
	}

}

function fetchWeb(res, req, feed, typeId, from, day, bool, callback) {
	var posts, feedFrom = from;

	function done(err) {
		if (cache.has(day) && cache.get(day)[feedFrom]) {
			console.log("-> read cache. " + day + " - " + feedFrom);
			callback(cache.get(day)[feedFrom], "cache");
		} else if (grunt.file.exists(path.resolve(dir + "/" + feedFrom + ".json"))) {
			console.log("-> read json file. " + feedFrom);
			posts = grunt.file.readJSON(path.resolve(dir + "/" + feedFrom + ".json"));
			cache.commit({
				[day]: {
					[feedFrom]: posts.data
				}
			});
			callback(posts, "file");
		} else {
			callback(err);
		}
	}
	// Define our streams  
	if (cache.has(day) && cache.get(day)[feedFrom]) {
		console.log("-> read cache. " + day + " - " + feedFrom);
		callback(cache.get(day)[feedFrom], "cache");
	} else if (grunt.file.exists(path.resolve(dir + "/" + feedFrom + ".json"))) {
		console.log("-> read json file. " + feedFrom);
		posts = grunt.file.readJSON(path.resolve(dir + "/" + feedFrom + ".json"));
		cache.commit({
			[day]: {
				[feedFrom]: posts.data
			}
		});
		callback(posts, "file");
	} else {
		console.log("fetchWeb ->");
		var fetchWebFn = require('node-fetch');
		var cheerio = require('cheerio');
		var url = require('url');

		res.header('Content-Type', 'application/xml; charset=utf-8');

		fetchWebFn(feed).then(
			response => response.text()
		).then((data) => {
			var $ = cheerio.load(data, {
				decodeEntities: false
			});
			var wbs = [];
			var items = $('.wgtCell');
			var wb, item, titleEle;
			items.map(function(index, ele) {
				wb = {};
				item = $(this);
				titleEle = item.find('.wgtCell_txt');
				wb.title = titleEle.text().replace(/^\s+|\s+$/g, '');
				if (wb.title.length > 24) {
					wb.title = wb.title.slice(0, 24) + '...';
				}
				wb.description = titleEle.html().replace(/\s+/g, ' ').replace(/thumbnail/, 'large').replace(/\r|\n/gim, " ");
				wb.pubDate = getTime(item.find('.link_d').html());
				wb.link = item.find('.wgtCell_tm a').attr('href');
				wbs.push(wb);
			});

			var posts = wbs;
			cache.commit({
				[day]: {
					[feedFrom]: wbs
				}
			});
			console.log("-> fetchWeb: read net file. " + feedFrom);
			var content = stringify(posts);
			console.log(path.resolve(dir + "/" + feedFrom + ".json"))
			grunt.file.write(path.resolve(dir + "/" + feedFrom + ".json"), "{\"data\":" + content + "}");
			callback(posts, "net");
		}).catch(function(error) {
			callback(error);
		});
	}
}

exports.getotherjson = function(res, query) {
	var a = grunt.file.readJSON("user/rss.json"),
		b = query.callback,
		c = query.channel || "baidu",
		l = query.count || 10;

	var day = (query.day || getTime(new Date(), "yyyyMMdd"));
	dir = "rss" + day;
	console.log(query, (new Date().getTime() - parseInt(query.key)) / 1000, 60);

	var bool = (!query.key || query.key === "null" || query.key && (new Date().getTime() - parseInt(query.key)) / 1000 > 60) ? true : false;
	if (bool) {
		startTime = (new Date().getTime());
	}

	fetchOtherJson(a.data[c].link, a.data[c].typeid, c, day, false, "utf-8", function(txt, type) {
		res.send({
			status: 1,
			data: txt.data || txt
		});
	});
};

function fetchOtherJson(feed, typeid, from, day, bool, local_charset, callback) {
	request(feed + (new Date()).getTime(), function(error, response, body) {
		if (!error && response.statusCode == 200) {
			var local_json = grunt.file.exists(path.resolve(dir + "/" + from + ".json")) && grunt.file.readJSON(path.resolve(dir + "/" + from + ".json")) || {
				data: []
			};
			var json = JSON.parse(body);
			for (var n in json.data) {
				local_json.data.push(json.data[n]);
			}
			json.data && grunt.file.write(path.resolve(dir + "/" + from + ".json"), "{\"data\":" + JSON.stringify(local_json.data) + "}");
			callback(local_json);
		}
	})
}

function sendMail(email, userinfo, key) {
	var nodemailer = require('nodemailer');
	var transporter = nodemailer.createTransport({
		//https://github.com/andris9/nodemailer-wellknown#supported-services 支持列表
		service: 'qq',
		port: 465, // SMTP 端口
		secureConnection: true, // 使用 SSL
		auth: {
			user: '18900360@qq.com',
			//这里密码不是qq密码，是你设置的smtp密码
			pass: 'xwffhknnjotkbgfa'
		}
	});

	// NB! No need to recreate the transporter object. You can use
	// the same transporter object for all e-mails

	// setup e-mail data with unicode symbols
	var mailOptions = {
		from: '18900360@qq.com', // 发件地址
		to: email, // 收件列表
		subject: 'Forgot password', // 标题
		//text和html两者只支持一种
		text: 'Forgot password', // 标题
		html: 'Click link,<a href="http://reg.iliulan.com/?channel=20170003&fpt=resetpassword&email=' + userinfo.email + '&k=' + key + '" target="_blank">Reset password</a>.' // html 内容
	};

	// send mail with defined transport object
	transporter.sendMail(mailOptions, function(error, info) {
		if (error) {
			return console.log(error);
		}
		console.log('Message sent: ' + info.response);

	});
}